package tp.badugi.net;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import tp.badugi.server.Server;

public class ServerNetworkingChannelTest {
	
	private class BasicServer implements Runnable {
		private ServerSocket serverSocket;
		private int port;
		ServerNetworkingChannel serverNetworkingChannel;
		
		public BasicServer(int port) {
			this.port = port;
		};
		
		@Override
		public void run() {
			try {
				serverSocket = new ServerSocket(port);
				Socket socket = serverSocket.accept();
				serverNetworkingChannel = new ServerNetworkingChannel(serverListener, socket);
				serverSocket.close();
				serverNetworkingChannel.run();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		public void terminate() {
			try {
				serverSocket.close();
			} catch (IOException e) { }
		}
		
		public ServerNetworkingChannel getServerNetworkingChannel() {
			return serverNetworkingChannel;
		}
	}
	
	private class BasicRequestListener implements iRequestListener {
		
		private ClientNetworkingChannel netChannel;
		
		public BasicRequestListener(ClientNetworkingChannel netChannel) {
			this.netChannel = netChannel;
		}
		
		@Override
		public void actionRequested(String[] possibleActions, long betAmount, 
				long minBet, int timeout) 
		{
			netChannel.respondToActionRequest(iRequestListener.ACTION_BET, 1000);
		}

		@Override
		public void cardsRequested(String[] currentCards, int timeout) {
			String[] chosenCards = new String[] {currentCards[2], currentCards[3]};
			netChannel.respondToCardsRequest(chosenCards);
		}
	}
	
	iServerRequestListener serverListener;
	
	@Before
	public void before() {
		serverListener = mock(iServerRequestListener.class);
	}

	@Test
	public void testRequestAction() throws Exception {
		// Prepare test case
		final int PORT = 3010;
		BasicServer server = new BasicServer(PORT);
		Thread serverThread = new Thread(server);
		serverThread.start();
		
		Thread.sleep(100);
		ClientNetworkingChannel client1 = new ClientNetworkingChannel("127.0.0.1", PORT);
		iRequestListener requestListener = new BasicRequestListener(client1);
		iStatusUpdateListener updateListener = mock(iStatusUpdateListener.class);
		client1.addRequestListener(requestListener);
		client1.addStatusUpdateListener(updateListener);
		client1.connect();
		
		// Prepare request
		String[] actions = new String[] {
				iRequestListener.ACTION_FOLD,
				iRequestListener.ACTION_BET,
				iRequestListener.ACTION_ALLIN};
		long[] contributions = new long[] {200, 400, 600, 0};
		long betAmount = 600;
		long minBet = 20;
		int timeout = 3000;
		
		// Send request
		ServerNetworkingChannel serverNetChannel = server.getServerNetworkingChannel();
		ActionRequestResponse response = 
				serverNetChannel.requestAction(actions, betAmount, minBet, timeout);
		
		// Clean up
		client1.disconnect();
		serverThread.interrupt();
		
		// Assert
		assertEquals(iRequestListener.ACTION_BET, response.action);
		assertEquals(1000, response.amount);
	}
	
	@Test
	public void testRequestCards() throws Exception {
		// Prepare test case
		final int PORT = 3020;
		BasicServer server = new BasicServer(PORT);
		Thread serverThread = new Thread(server);
		serverThread.start();
		
		Thread.sleep(100);
		ClientNetworkingChannel client1 = new ClientNetworkingChannel("127.0.0.1", PORT);
		iRequestListener requestListener = new BasicRequestListener(client1);
		iStatusUpdateListener updateListener = mock(iStatusUpdateListener.class);
		client1.addRequestListener(requestListener);
		client1.addStatusUpdateListener(updateListener);
		client1.connect();
		
		// Prepare request
		String[] cards = new String[] {"AS", "2C", "3H", "4D"};
		int timeout = 3000;
		
		// Send request
		Thread.sleep(100);
		ServerNetworkingChannel serverNetChannel = server.getServerNetworkingChannel();
		String[] response = serverNetChannel.requestCards(cards, timeout);
		
		// Clean up
		client1.disconnect();
		serverThread.interrupt();
		
		// Assert
		assertEquals("3H", response[0]);
		assertEquals("4D", response[1]);
	}

}
